package org.example.client.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.example.client.client.handler.NettyClientHandlerInitializer;
import org.example.common.codec.Invocation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @title
 * @time 2025/6/16 23:31
 */
@Component
@Slf4j
public class NettyClient {
    /**
     * 重连间隔时间 单位:秒
     */
    private static final Integer RECONNECT_SECONDS = 20;
    /**
     * 最大重连次数
     */
    private static final Integer MAX_RECONNECT_ATTEMPTS = 3;
    /**
     * 当前重连次数
     */
    private AtomicInteger reconnectAttempts = new AtomicInteger(0);

    private String serverHost = "127.0.0.1";
    private Integer serverPort = 9000;
    /**
     * 线程组:用于客户端对服务端的链接、数据读写
     */
    private EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
    private volatile Channel channel;

    @Autowired
    private NettyClientHandlerInitializer nettyClientHandlerInitializer;

    /**
     * 启动 Netty  Client
     */
    @PostConstruct
    public void start() throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(eventLoopGroup)
                .channel(NioSocketChannel.class)
                .remoteAddress(serverHost, serverPort)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(nettyClientHandlerInitializer);
        // 连接服务器，并异步等待成功，既启动客户端
        bootstrap.connect().addListener((ChannelFutureListener) future -> {
            if (!future.isSuccess()) {
                log.error("启动 Netty Client 失败，连接服务器[{}:{}] 失败",serverHost, serverPort);
                reconnct();
                if (reconnectAttempts.get() < MAX_RECONNECT_ATTEMPTS) {
                    log.info("[即将开始重连] 次数:{}", reconnectAttempts.get());
                }
                return;
            }
            channel = future.channel();
            // 重连成功，重置计数器
            reconnectAttempts.set(0);
            log.warn("启动 Netty Client 成功,连接({}),连接服务器[{}:{}] 成功",channel.id(),serverHost, serverPort);
        });
    }

    public void reconnct() {
        if (reconnectAttempts.get() >= MAX_RECONNECT_ATTEMPTS) {
            log.error("[reconnect][达到最大重连次数({})，停止重连]", MAX_RECONNECT_ATTEMPTS);
            return;
        }
        // 原子性增加重连次数
        int attempts = reconnectAttempts.incrementAndGet();
        eventLoopGroup.schedule(() -> {
            log.info("[reconnct][准备重连] 当前重连次数: {}", attempts);
            try {
                start();
            } catch (InterruptedException e) {
                log.error("重连失败", e);
            }
        }, RECONNECT_SECONDS, TimeUnit.SECONDS);
    }

    /**
     * 关闭 Netty Client
     */
    @PreDestroy
    public void shutdown() {
        if (channel != null) {
            channel.close();
        }
        eventLoopGroup.shutdownGracefully();
    }

    /**
     * 发送消息
     */
    public void send(Invocation invocation) {
        if (channel == null) {
            log.error("[send][连接不存在]");
            return;
        }
        if (!channel.isActive()) {
            log.error("[send][连接({})未激活]", channel.id());
            return;
        }
        // 发送消息
        channel.writeAndFlush(invocation);
    }
}
